-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add inverse for CartesianPose and define operators explicitely #158
Conversation
4c91144
to
9dfe1ab
Compare
@@ -123,6 +135,25 @@ Eigen::VectorXd CartesianPose::data() const { | |||
return this->get_pose(); | |||
} | |||
|
|||
CartesianPose CartesianPose::inverse() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not use the CartesianState::inverse() and then downcast the return back to a pose? it would prevent some code duplication, and I would say the few extra linear operations are not hugely costly. It's also how the other operators are working anyway
* @brief Compute the inverse of the current CartesianPose | ||
* @return the inverse corresponding to b_S_f (assuming this is f_S_b) | ||
*/ | ||
CartesianPose inverse() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CartesianState inverse() const
is not deleted in this header, which means this new declaration is hiding the base method. It would be safer to delete the base inverse method in this header as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I add the line
CartesianState inverse() const = delete;
to the CartesianPose header, I cannot build state_representation anymore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, my bad. Then instead you should mark the CartesianState::inverse as virtual and explicitly override the derived version here.
// in CartesianState.hpp
virtual CartesianState CartesianState::inverse() const;
// in CartesianPose.hpp
CartesianPose CartesianPose::inverse() const override;
This should work because the return type of the derived function is a co-variant (the derived class) of the base function (the base class).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that doesn't work unfortunately... Even though it should...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, there are other functions like that (the copy
one) that are not defined virtual or deleted but that hide the CartesianState function
@@ -47,6 +47,9 @@ class CartesianTwist : public CartesianState { | |||
void set_force(const Eigen::Vector3d& force) = delete; | |||
void set_torque(const Eigen::Vector3d& torque) = delete; | |||
void set_wrench(const Eigen::Matrix<double, 6, 1>& wrench) = delete; | |||
CartesianState inverse() const = delete; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Contrary to what @buschbapti mentioned on slack, I believe the inverse function still makes sense for the twist and the wrench. In the absence of any pose orientation, a pure twist inverse would simply be the negation of the linear and angular vectors (plus swapping the reference frame). But, as with the pose, you can still call the base CartesianState::inverse and downcast the return.
* @param twist CartesianTwist to multiply with | ||
* @return the current CartesianTwist multiplied by the CartesianTwist given in argument | ||
*/ | ||
CartesianTwist& operator*=(const CartesianTwist& twist); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to avoid another major version increment to control libraries 4.0, then the correct approach would be to mark these function as deprecated instead of deleting them:
[[deprecated]] CartesianTwist& operator*=(const CartesianTwist& twist);
Same goes for the base functions (e.g. CartesianState operator*(const CartesianState& state)
), instead of deleting you would override / hide the implementation and mark it as deprecated. (hiding in this context is ok, since we don't intend the method to actually be used)
We could then remove these cases entirely the next time we decide to release a new major version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get the first part but not the second one. Do I have to explicitly add the operator CartesianState operator*(const CartesianState& state)
in the header and source (where i just call the CartesianState operator) and then mark them as deprecated in the header?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes exactly, for the second part you would have to re-implement those functions for this class. It may be more effort than it is worth, that's up to you and @buschbapti to decide. The first part I think still makes sense though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll see if the tests pass without, otherwise it may be necessary.
I marked the operators as deprecated like you proposed. However, the inverse functions now hide the one of the base class. I can't say if this a good solution or not but i think it's better than before. |
To be frank, it was maybe not our best idea to go down this road but it's always good to think about those things in detail. Here are my propositions:
We can also leave this here and come back to it when you guys have more time to think about it. And if we go through with it we remove the operators with the next major version release. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is the right road to go down, even if it's a little messy in the interim. By first explicitly marking out everything as deprecated, I think we can get a good idea of the implications without committing to a breaking change right away.
I agree with the overall rules that have emerged for product operations, which I will restate again for the record:
- The return type of a product operation is the same as the right operand
- The left operand of a product operation can only be
CartesianPose
orCartesianState
I'm going to give this one more thorough pass before approving but I appreciate the effort and the design direction.
@@ -148,7 +150,7 @@ class CartesianPose : public CartesianState { | |||
* @param pose CartesianPose to multiply with | |||
* @return the current CartesianPose multiplied by the CartesianPose given in argument | |||
*/ | |||
CartesianPose& operator*=(const CartesianPose& pose); | |||
[[deprecated]] CartesianPose& operator*=(const CartesianPose& pose); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These pose *= pose and state *= state operators are the ones that actually do make sense, as you mentioned in your comment - so why have you deprecated it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I undersrand correctly we have two choices for the *= operator. Either we delete it completely or we have it in CartesianState, override it in CartesianPose and delete it in Wrench and Twist. And i was going for the first option hehe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well I would prefer the second option though *=
for pose and state make sense so I would keep them and just delete them in the velocity and wrench
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah but let's face it then, either we have breaking changes or we postpone the *= operator until the next major release. Otherwise I have to implement every combination and mark them as deprecated instead of just deleting them where I can
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to go in the right direction thanks for that.
@@ -379,7 +379,7 @@ class CartesianState : public SpatialState { | |||
* @param state the state to compose with corresponding to b_S_c | |||
* @return the CartesianState corresponding f_S_c = f_S_b * b_S_c (assuming this is f_S_b) | |||
*/ | |||
CartesianState& operator*=(const CartesianState& state); | |||
[[deprecated]] CartesianState& operator*=(const CartesianState& state); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment as for the pose I would actually keep that one
* @param state CartesianPose to multiply with | ||
* @return the current CartesianTwist multiplied by the CartesianPose given in argument | ||
*/ | ||
[[deprecated]] CartesianPose operator*(const CartesianPose& pose) const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need to deprecate this one? It was actually never implemented explicitly before. I think you can just deprecate the one with state and leave off the other ones otherwise you introduce also some forward declaration for wrench that is not needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok I think I understand that you need those to mark them as removed, as you don't want to deprecate the operator*
which will be called if those are not implemented. Is that correct? Then yes I guess no other choices and forget the other comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes indeed, thats what you also said, if we explicitly implement one, we need to do all of them :)
* @param state CartesianWrench to multiply with | ||
* @return the current CartesianTwist multiplied by the CartesianWrench given in argument | ||
*/ | ||
[[deprecated]] CartesianWrench operator*(const CartesianWrench& wrench) const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
|
||
namespace state_representation { | ||
class CartesianPose; | ||
class CartesianTwist; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as for the twist so I don't think this is needed
@@ -123,6 +135,11 @@ Eigen::VectorXd CartesianPose::data() const { | |||
return this->get_pose(); | |||
} | |||
|
|||
CartesianPose CartesianPose::inverse() const { | |||
CartesianPose result = this->CartesianState::inverse(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use the same writing in one liner as above in the operator*
. I assume the compiler would then cast correctly as you specify the return type
@@ -144,6 +161,10 @@ std::ostream& operator<<(std::ostream& os, const CartesianPose& pose) { | |||
return os; | |||
} | |||
|
|||
CartesianPose operator*(const CartesianState& state, const CartesianPose& pose) { | |||
return CartesianPose(state.operator*(pose)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above. If the compiler does the casting for you then no need to explicitly specify it. Otherwise you need to specify it in the other operator*
for consistency.
return (*this); | ||
} | ||
|
||
CartesianState CartesianState::operator*(const CartesianState& state) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure why you changed that here. So basically, the previous version was defining this in operator*=
, then calling it in this operator*
. Here you do the opposite, defining it here and calling this operator in the *=
one. I don't really have a preference but all the other operators are defined following the first rule so I would prefer avoiding this change for consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there might also be some optimization under the hood doing it as it was as most of the operator overloading do it that way.
04cab11
to
fa4bcf9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for changing the casts in pose there are still some left in twist and wrench
@@ -122,6 +140,10 @@ std::ostream& operator<<(std::ostream& os, const CartesianWrench& wrench) { | |||
return os; | |||
} | |||
|
|||
CartesianWrench operator*(const CartesianState& state, const CartesianWrench& wrench) { | |||
return CartesianWrench(state.operator*(wrench)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as with pose which I have seen as now been corrected
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oups yeah sorry, early mornings....
@@ -149,6 +163,11 @@ Eigen::VectorXd CartesianTwist::data() const { | |||
return this->get_twist(); | |||
} | |||
|
|||
CartesianTwist CartesianTwist::inverse() const { | |||
CartesianTwist result = this->CartesianState::inverse(); | |||
return result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as with pose which I have seen as now been corrected
@@ -164,6 +183,10 @@ std::ostream& operator<<(std::ostream& os, const CartesianTwist& twist) { | |||
return os; | |||
} | |||
|
|||
CartesianTwist operator*(const CartesianState& state, const CartesianTwist& twist) { | |||
return CartesianTwist(state.operator*(twist)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as with pose which I have seen as now been corrected
c2f8c32
to
078a3a5
Compare
I will try to add a few more tests so maybe you can wait with your final reviwe 👍 |
078a3a5
to
98d7cc0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can pass for a 3.1 release, with the mentioned TODOs for the next release
d7b8977
to
b8822f4
Compare
Sooo issue #156 made us think about the operators a bit more and we came to the conclusion that
That said, I deleted the
*
operators for twist and wrench, and added explicit*
operators for the pose.I expect that this might change again during this PR, which is why I'm waiting with the CHANGELOG and pybindings.